package org.threebitsoftware.tbb.dao.bridge;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;

import org.apache.log4j.Logger;
import org.threebitsoftware.dao.generated.AddressKey;
import org.threebitsoftware.dao.generated.dao.AddressDAO;
import org.threebitsoftware.dao.generated.orm.AddressDAOImpl;
import org.threebitsoftware.tbb.dao.Address;
import org.threebitsoftware.tbb.dao.Contact;
import org.threebitsoftware.tbb.dao.DaoHelper;

import com.pew.util.dao.DatabaseUtil;

/*
 * Created: Nov 14, 2009
 * Original Author: Elwin
 * Project:
 * Copyright:
 * 
 * Purpose:
 */

/*
 * Copyright (c) 2009, 3BitSoftware
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *   * Neither the name of the <organization> nor the
 *     names of its contributors may be used to endorse or promote products
 *     derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY <copyright holder> ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

public class AddressBridge {
	private static Logger cLogger = Logger.getLogger(AddressBridge.class);
	public static void storeAddress(Address myObject)
	{
		AddressDAO lDAO = new AddressDAOImpl();
		
		cLogger.debug("Attempting to store an Address.");
		try {
		
			if(myObject.isMarkedForDeletion())
			{
				cLogger.debug("Found delete for: " + myObject.toString());
				if(myObject.getIdContact() > -1)
				{
					AddressKey lKey = new AddressKey();
					lKey.setIdAddress(myObject.getIdAddress());
					lDAO.delete(lKey, DaoHelper.getDBConnection());
				}
				else
				{
					cLogger.info("Nothting to do for Contact:" + myObject.toString() + "; it is not in the database based; decesion on no ID.");
				}
			}
			else
			{
				create(lDAO, myObject);
			}
		}
		catch(SQLException sqlex)
		{
			cLogger.error("An exception occured while trying to perform an operation to: " + myObject.toString());
			cLogger.error(sqlex.toString());
		}
	}
	
	/**
	 * Stores multiple objects into the storage medium.
	 * @param myContact ; An array of objects.
	 */
	public static void storeContact(Address myObject[])
	{
		cLogger.debug("Entered storeContact(myContact[])");
		
		int liSize = myObject.length;
		for(int i = 0; i < liSize; i++) {
			storeAddress(myObject[i]);
		}
		
		cLogger.info("Worked on storing " + liSize + " phone numbers.");
		
	}
	
	/**
	 * Retrieves an object based on the unique
	 * id passed into it.
	 * @param myId ; A unique identifier for a Contact
	 * @return A Contact object; null if none exists or an error occurs.
	 */
	public static Address getAddress(int myId)
	{
		Address lDomainObject = null;
		org.threebitsoftware.dao.generated.Address lDaoObject = null;
		
		cLogger.debug("Getting a DAO object for id: " + myId);
		
		AddressDAO lDAO = new AddressDAOImpl();
		AddressKey lKey = new AddressKey();
		
		lKey.setIdAddress((new Integer(myId)).longValue());
		
		try {
			lDaoObject = lDAO.load(lKey, DaoHelper.getDBConnection());
		}
		catch(SQLException sqlex)
		{
			cLogger.error("Error retrieving phone number with id:" + myId, sqlex);
		}
		
		lDomainObject = mapDaoToDomain(lDaoObject);
		
		return lDomainObject;
	}
	
	
	/**
	 * Retrieves multiple objects based on a 
	 * SQL-92 based conditional clause.
	 * @return An array of Contact objects; null if an error occurs.
	 */
	public static Address[] getAddresses(String myQuery, int myAppId)
	{
		cLogger.debug("Attempting to gather multiple domain objects based" +
				" on id query: " + myQuery + " and app user id" + myAppId);
		
		Address lDomainList[] = null;
		cLogger.debug("Attempting to gather multiple domain objects based" +
				" on id query: " + myQuery);
		
		ArrayList<Address> lDomainListColl = new ArrayList<Address>();
		ResultSet lRS = null;
		
		lRS = DatabaseUtil.runSelectStatement(DaoHelper.getDBConnection(),
				"SELECT ID_ADDRESS FROM ADDRESS WHERE " + myQuery);
		int lTempId =  -1;
		int i = 0;
		
		try {
			cLogger.debug("The query returned:" + lRS.getFetchSize());

			while(lRS.next()) {
				lTempId = lRS.getInt(1);
				lDomainListColl.add(getAddress(lTempId));
			}
		}
		catch (SQLException sqlex)
		{
			cLogger.error("Exception occured while getting contacts based on"
					+ " query: " + myQuery, sqlex);
		}
		
		lDomainList = new Address[lDomainListColl.size()];
		int count = 0;
		for(Address c : lDomainListColl) {
			lDomainList[count] = c;
			count++;
		}
		System.out.println("Array lDomainList: \t" + lDomainList.length + "\t\tlDomainListColl: \t" + lDomainListColl.size());
		return lDomainList;

	}
	
	
	/**
	 * Maps the dao object to the domain object.
	 * @param myDaoObject
	 * @return A filled domain object; null if failure.
	 */
	public static Address mapDaoToDomain(org.threebitsoftware.dao.generated.Address myDaoObject) {
		cLogger.debug("Attempting to map a dao to a domain object.");
		
		Address lDomain = null;
		if(myDaoObject != null)
		{
			lDomain = new Address();
			lDomain.setStreet1(myDaoObject.getSStreetA());
			lDomain.setStreet2(myDaoObject.getSStreetB());
			lDomain.setStreet3(myDaoObject.getSStreetC());
			lDomain.setCity(myDaoObject.getSCity());
			lDomain.setProvince(myDaoObject.getSProvince());
			lDomain.setCountry(myDaoObject.getSCountry());
			lDomain.setDescription(myDaoObject.getSDescription());
			lDomain.setIdContact((new Long(myDaoObject.getIdContact())).intValue());
			lDomain.setZipCode(myDaoObject.getSZipcode());
			lDomain.setIdAddress((new Long(myDaoObject.getIdAddress())).intValue());
			lDomain.setIdAppUser((new Long(myDaoObject.getIdAppUser())).intValue());
			
			cLogger.debug("Filled with: " + lDomain.toString());
		}
		else if(cLogger.isDebugEnabled())
		{
			cLogger.debug("No DAO object to be mapped.");
		}
		
		return lDomain;
	}
	
	/**
	 * Maps the domain object 
	 * @param myDomainObject
	 * @return
	 */
	public static org.threebitsoftware.dao.generated.Address mapDomainToDao(Address myDomainObject) {
		
		cLogger.debug("Attempting to map a Domain object to a dao object");
		
		org.threebitsoftware.dao.generated.Address lDaoObject = null;
		
		if(myDomainObject != null )
		{
			lDaoObject = new org.threebitsoftware.dao.generated.Address();
			lDaoObject.setIdContact((new Integer(myDomainObject.getIdContact())).longValue());
			lDaoObject.setSDescription(myDomainObject.getDescription());
			
			lDaoObject.setIdAddress((new Integer(myDomainObject.getIdAddress())).longValue());
			lDaoObject.setIdAppUser((new Integer(myDomainObject.getIdAppUser())).longValue());
			lDaoObject.setSStreetA(myDomainObject.getStreet1());
			lDaoObject.setSStreetB(myDomainObject.getStreet2());
			lDaoObject.setSStreetC(myDomainObject.getStreet3());
			lDaoObject.setSCity(myDomainObject.getCity());
			lDaoObject.setSProvince(myDomainObject.getProvince());
			lDaoObject.setSCountry(myDomainObject.getCountry());
			lDaoObject.setSZipcode(myDomainObject.getZipCode());
			
			cLogger.debug("Done filling.  Filled with: " + lDaoObject.toString());
		}
		else if(cLogger.isDebugEnabled())
		{
			cLogger.debug("Nothing to map.");
		}
		
		cLogger.debug("Done with filling a dao object.");
		
		return lDaoObject;
	}
	
	/**
	 * Create or updates an object.
	 * @param myDAO T
	 * @param myObject
	 */
	static int create(AddressDAO myDAO, Address myObject) throws SQLException
	{
		org.threebitsoftware.dao.generated.Address lDaoObject = mapDomainToDao(myObject);
		String lClassName = myObject.getClass().getName();
		int liReturnId = -1;
		
		cLogger.debug("Attempting to create / update a " + lClassName);		
		
		
		
		if(lDaoObject.getIdAddress() > -1)
		{
			cLogger.debug("Attempt to Update Object: " + lClassName + " = " + myObject.getIdAddress());
			myDAO.update(lDaoObject, DaoHelper.getDBConnection());
			
			cLogger.info("Done updating" + lClassName);
		}
		else
		{
			cLogger.debug("New" + lClassName + " Detected; id is -1.");
			
			//Logic here assists in testing and other special cases.
			
			if(lDaoObject.getIdAddress() == -1)
			{
				cLogger.debug("Current id is -1; getting a new id.");
				int liNewId = DaoHelper.getNextId("Address", "ID_ADDRESS", DaoHelper.getDBConnection());
				cLogger.debug("Got id: " + liNewId);
				
				lDaoObject.setIdAddress(new Integer(liNewId).longValue());
			}
			else if(cLogger.isDebugEnabled())
			{
				cLogger.debug("Id is not -1; creating a new object with the current id.");
			}
			
			myDAO.create(lDaoObject, DaoHelper.getDBConnection());
			
			cLogger.info("Created a new" + lClassName);
		}
		
		liReturnId = (new Long(lDaoObject.getIdAddress()).intValue());
		myObject.setIdAddress(liReturnId);
		
		cLogger.info("Id worked on " + liReturnId + " for " + lClassName);
		cLogger.debug("Done creating or editing an object");
		
		return liReturnId;
	}

}
